<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>舒尔特方格</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        height: 100vh;
      }

      #canvas {
        border: 1px solid black;
      }
      #display {
        font-size: 48px;
        margin-bottom: 20px;
      }
      #slider {
        width: 50%;
        margin-top: 10px;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas"></canvas>
    <input type="range" id="slider" min="2" max="16" value="4" />
    <div id="display">00:00:00.000</div>

    <script>
      class NumberGame {
        constructor(cellCount) {
          this.cellCount = cellCount;
          this.numbers = new Array(cellCount * cellCount);
          this.expectNumber = 1;
          for (let i = 1; i <= cellCount * cellCount; i++) {
            this.numbers[i - 1] = i;
          }
          shuffleArray(this.numbers);
        }

        numberAt(row, col) {
          let index = row * this.cellCount + col;
          return this.numbers[index];
        }

        isClickGood(row, col) {
          let n = this.numberAt(row, col);
          if (n == this.expectNumber) {
            this.expectNumber++;
            return true;
          }
          return false;
        }

        isGameSuccess() {
          return this.expectNumber > this.numbers.length;
        }
      }

      function shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
          const j = Math.floor(Math.random() * (i + 1));
          [array[i], array[j]] = [array[j], array[i]];
        }
      }

      function formatTime(milliseconds) {
        let hours = Math.floor(milliseconds / 3600000);
        let minutes = Math.floor((milliseconds - hours * 3600000) / 60000);
        let seconds = Math.floor(
          (milliseconds - hours * 3600000 - minutes * 60000) / 1000
        );
        let ms =
          milliseconds - hours * 3600000 - minutes * 60000 - seconds * 1000;

        hours = hours.toString().padStart(2, "0");
        minutes = minutes.toString().padStart(2, "0");
        seconds = seconds.toString().padStart(2, "0");
        ms = ms.toString().padStart(3, "0");

        return `${hours}:${minutes}:${seconds}.${ms}`;
      }
      let intervalId = 0;

      function startTimer() {
        startTime = Date.now() - elapsedTime;
        intervalId = setInterval(() => {
          elapsedTime = Date.now() - startTime;
          display.textContent = formatTime(elapsedTime);
        }, 300);
      }

      function stopTimer() {
        if (intervalId != 0) {
          clearInterval(intervalId);
          intervalId = 0;
        }
      }

      function resetTimer() {
        elapsedTime = 0;
        display.textContent = formatTime(elapsedTime);
      }

      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      const slider = document.getElementById("slider");
      let game = null;
      const goodAudio = new Audio(
        "https://www.soundjay.com/buttons/beep-08b.mp3"
      );
      const badAudio = new Audio(
        "https://www.soundjay.com/buttons/button-6.mp3"
      );
      const successAudio = new Audio(
        "https://www.soundjay.com/buttons/button-2.mp3"
      );

      let cellCount = parseInt(slider.value);
      const colors = ["#f9e6d2", "#e2f2e4", "#f2ead6", "#e6d9f9"];

      function drawGrid() {
        const gridSize = Math.min(window.innerWidth, window.innerHeight) / 1.2;
        const cellSize = gridSize / cellCount;

        canvas.width = gridSize;
        canvas.height = gridSize;

        for (let row = 0; row < cellCount; row++) {
          for (let col = 0; col < cellCount; col++) {
            let colorIndex = Math.floor(Math.random() * colors.length);
            let color = colors[colorIndex];

            ctx.fillStyle = color;
            ctx.fillRect(col * cellSize, row * cellSize, cellSize, cellSize);

            // Draw cell border in white
            ctx.strokeStyle = "white";
            ctx.strokeRect(col * cellSize, row * cellSize, cellSize, cellSize);

            // Draw text in the center of the cell
            ctx.fillStyle = "black";
            ctx.font = "48px Arial";
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            ctx.fillText(
              `${game.numberAt(row, col)}`,
              col * cellSize + cellSize / 2,
              row * cellSize + cellSize / 2
            );
          }
        }
      }

      function restartGame() {
        game = new NumberGame(cellCount);
        drawGrid();
        stopTimer();
        resetTimer();
        startTimer();
      }

      restartGame();
      window.addEventListener("resize", drawGrid);

      canvas.addEventListener("click", handleClick);

      function handleClick(event) {
        const gridSize = Math.min(window.innerWidth, window.innerHeight) / 1.2;
        const cellSize = gridSize / cellCount;
        const row = Math.floor(event.offsetY / cellSize);
        const col = Math.floor(event.offsetX / cellSize);
        if (game == null) {
          restartGame();
          return;
        }

        if (game.isClickGood(row, col)) {
          if (!goodAudio.paused) {
            goodAudio.pause();
            goodAudio.currentTime = 0;
          }
          goodAudio.play();
          if (game.isGameSuccess()) {
            stopTimer();
            successAudio.play();
            game = null;
          }
        } else {
          badAudio.play();
        }
      }

      slider.addEventListener("input", handleSlider);

      function handleSlider(event) {
        cellCount = parseInt(event.target.value);
        restartGame();
      }
    </script>
  </body>
</html>
